/*
 * InvitigateBinaryNodeTest.cpp
 *
 *  Created on: Feb 1, 2010
 *      Author: anton.kuhlevskyi
 */

// Google test includes
#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include <memory>

// Tested file
#include "Nodes/Investigate/Node.h"

// Set dynamic binary node
typedef NodeTraits<_BaseBinaryNode<false> >::Node		BinaryNode;
typedef NodeTraits<_BaseBinaryNode<false> >::NodeAtom	BinaryNodeAtom;
typedef NodeTraits<_BaseBinaryNode<false> >::NodeAnd	BinaryNodeAnd;
typedef NodeTraits<_BaseBinaryNode<false> >::NodeOr		BinaryNodeOr;
typedef NodeTraits<_BaseBinaryNode<false> >::NodeNot	BinaryNodeNot;

TEST(InvestigateBinaryNodeTest, AtomCreate)
{
	BinaryNodeAtom atom("test");

	// Verify node attributes
	EXPECT_EQ(NT_ATOM, atom.getNodeType());
	EXPECT_EQ(0, atom.getChildrenCount());
	EXPECT_EQ("test", atom.getAtomText());
}

TEST(InvestigateBinaryNodeTest, AtomClone)
{
	BinaryNodeAtom atom("test");

	// Clone the node
	std::auto_ptr<BinaryNode> clone(atom.clone());

	// Verify node attributes
	EXPECT_EQ(0, clone->getChildrenCount());
	ASSERT_EQ(NT_ATOM, clone->getNodeType());
	EXPECT_EQ("test", static_cast<BinaryNodeAtom*>(clone.get())->getAtomText());
}

TEST(InvestigateBinaryNodeTest, AtomCompare1)
{
	BinaryNodeAtom atom("test");

	// Verify that atom node does not equals other node types
	BinaryNodeNot ref(NULL);
	EXPECT_FALSE(atom.compare(&ref));
}

TEST(InvestigateBinaryNodeTest, AtomCompare2)
{
	BinaryNodeAtom atom("test");

	// Verify that two atoms differs when their text differs
	BinaryNodeAtom ref("not_test");
	EXPECT_FALSE(atom.compare(&ref));
}

TEST(InvestigateBinaryNodeTest, AtomCompare3)
{
	BinaryNodeAtom atom("test");

	// Verify that two atoms equals when their text equals
	BinaryNodeAtom ref("test");
	EXPECT_TRUE(atom.compare(&ref));
}

TEST(InvestigateBinaryNodeTest, NotCreate)
{
	// Prepare children
	BinaryNodeAtom * child = new BinaryNodeAtom("child");

	// Prepare tested node
	BinaryNodeNot nodeNot(child);

	// Verify node attributes
	EXPECT_EQ(NT_NOT, nodeNot.getNodeType());
	EXPECT_EQ(1, nodeNot.getChildrenCount());
	EXPECT_EQ(child, nodeNot.getChild(0));
}

TEST(InvestigateBinaryNodeTest, NotClone)
{
	// Prepare children
	BinaryNodeAtom * child = new BinaryNodeAtom("child");

	// Prepare tested node
	BinaryNodeNot nodeNot(child);

	// Create the clone
	std::auto_ptr<BinaryNode> clone(nodeNot.clone());

	// Verify node attributes
	EXPECT_EQ(NT_NOT, clone->getNodeType());
	EXPECT_EQ(1, clone->getChildrenCount());
	EXPECT_TRUE(clone->getChild(0)->compare(child));
}

TEST(InvestigateBinaryNodeTest, AndCreate)
{
	// Prepare children
	BinaryNodeAtom * child0 = new BinaryNodeAtom("child0");
	BinaryNodeAtom * child1 = new BinaryNodeAtom("child1");

	// Prepare tested node
	BinaryNodeAnd nodeAnd(child0, child1);

	// Verify node attributes
	EXPECT_EQ(NT_AND, nodeAnd.getNodeType());
	EXPECT_EQ(2, nodeAnd.getChildrenCount());
	EXPECT_EQ(child0, nodeAnd.getChild(0));
	EXPECT_EQ(child1, nodeAnd.getChild(1));
}

TEST(InvestigateBinaryNodeTest, AndClone)
{
	// Prepare children
	BinaryNodeAtom * child0 = new BinaryNodeAtom("child0");
	BinaryNodeAtom * child1 = new BinaryNodeAtom("child1");

	// Prepare tested node
	BinaryNodeAnd nodeAnd(child0, child1);

	// Create the clone
	std::auto_ptr<BinaryNode> clone(nodeAnd.clone());

	// Verify node attributes
	EXPECT_EQ(NT_AND, clone->getNodeType());
	EXPECT_EQ(2, clone->getChildrenCount());
	EXPECT_TRUE(clone->getChild(0)->compare(child0));
	EXPECT_TRUE(clone->getChild(1)->compare(child1));
}

TEST(InvestigateBinaryNodeTest, OrCreate)
{
	// Prepare children
	BinaryNodeAtom * child0 = new BinaryNodeAtom("child0");
	BinaryNodeAtom * child1 = new BinaryNodeAtom("child1");

	// Prepare tested node
	BinaryNodeOr nodeOr(child0, child1);

	// Verify node attributes
	EXPECT_EQ(NT_OR, nodeOr.getNodeType());
	EXPECT_EQ(2, nodeOr.getChildrenCount());
	EXPECT_EQ(child0, nodeOr.getChild(0));
	EXPECT_EQ(child1, nodeOr.getChild(1));
}

TEST(InvestigateBinaryNodeTest, OrClone)
{
	// Prepare children
	BinaryNodeAtom * child0 = new BinaryNodeAtom("child0");
	BinaryNodeAtom * child1 = new BinaryNodeAtom("child1");

	// Prepare tested node
	BinaryNodeOr nodeOr(child0, child1);

	// Create the clone
	std::auto_ptr<BinaryNode> clone(nodeOr.clone());

	// Verify node attributes
	EXPECT_EQ(NT_OR, clone->getNodeType());
	EXPECT_EQ(2, clone->getChildrenCount());
	EXPECT_TRUE(clone->getChild(0)->compare(child0));
	EXPECT_TRUE(clone->getChild(1)->compare(child1));
}

TEST(InvestigateBinaryNodeTest, GetNotExistentChild)
{
	// Prepare children
	BinaryNodeAtom * child = new BinaryNodeAtom("child");

	// Prepare tested node
	BinaryNodeNot nodeNot(child);

	// Expect that number of children is not more that required
	EXPECT_THROW(nodeNot.getChild(1), std::runtime_error);
	EXPECT_THROW(child->getChild(0), std::runtime_error);
}

TEST(InvestigateBinaryNodeTest, SetChildToNode)
{
	// Prepare children
	BinaryNodeAtom * child1 = new BinaryNodeAtom("child1");
	BinaryNodeAtom * child2 = new BinaryNodeAtom("child2");

	// Prepare tested node
	BinaryNodeNot nodeNot(child1);

	// set new child
	EXPECT_NO_THROW(nodeNot.setChild(0, child2));
	EXPECT_EQ(child2, nodeNot.getChild(0));

	delete child1;
}

TEST(InvestigateBinaryNodeTest, SetChildToOutofNodeRange)
{
	// Prepare children
	BinaryNodeAtom * child = new BinaryNodeAtom("child");

	// Prepare tested node
	BinaryNodeAtom nodeAtom("atom");

	// set new child
	EXPECT_THROW(nodeAtom.setChild(0, child), std::runtime_error);

	delete child;
}
